using System;
using System.Collections.Generic;
using System.Text;

using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

using System.IO;

using Athena.Objects; 

namespace Athena
{
    public class Utility
    {
        public Utility() { }

        public static string CurrentDirectory
        {
            get { return Application.StartupPath; }
        }

        public static string GetJarnac()
        {
            return GetJarnac(Program.Model);
        }

        public static bool ShowToolTip
        {
            get
            {
                if (Program.Form != null)
                    return Program.Form.drawPanel1.ShowQuickTip;
                return false;
            }
            set
            {
                if (Program.Form != null)
                    Program.Form.drawPanel1.ShowQuickTip = value;
            }
        }

        public static string GetJarnac(Model model)
        {
            /*MemoryStream oStream = new MemoryStream();
            Athena.IO.JarnacWriter oWriter = new Athena.IO.JarnacWriter(oStream);
            oWriter.WriteModel(model);
            oStream.Flush();
            oStream.Seek(0, SeekOrigin.Begin);
            StreamReader oReader = new StreamReader(oStream);
            string sJarnac = oReader.ReadToEnd();
            return sJarnac;*/
            if (model == null || model.BackEndModel == null)
                return "";
            else
                return model.BackEndModel.JarnacScript;
        }

        public static string GetSBML()
        {
            return GetSBML(Program.Model);
        }

        public static float CurrentScale
        {
            get
            {
                return GetCanvas().ScaleFactor;
            }
        }
        public static PointF CurrentOffset
        {
            get
            {
                return GetCanvas().Offset;
            }
        }
        public static string GetSBML(string sJarnac)
        {
            MemoryStream oStream = new MemoryStream();
            Athena.IO.SBMLWriter oWriter = new Athena.IO.SBMLWriter(oStream);
            oWriter.WriteLayout = false;
            oWriter.Model = Program.Model;
            oWriter.WriteModelFromJarnac(sJarnac);
            oStream.Flush();
            oStream.Seek(0, SeekOrigin.Begin);
            StreamReader oReader = new StreamReader(oStream);
            string sSBML = oReader.ReadToEnd();
            return sSBML;
        }
        public static string GetSBML(Model model, bool bCreateLayout)
        {
            MemoryStream oStream = new MemoryStream();
            Athena.IO.SBMLWriter oWriter = new Athena.IO.SBMLWriter(oStream);
            oWriter.WriteLayout = bCreateLayout;
            oWriter.WriteModel(model);
            oStream.Flush();
            oStream.Seek(0, SeekOrigin.Begin);
            StreamReader oReader = new StreamReader(oStream);
            string sSBML = oReader.ReadToEnd();
            return sSBML;
        }
        public static string GetSBML(Model model)
        {
            return GetSBML(model, true);
        }


        public static string DocumentsDirectory
        {
            get
            {
                return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            }
        }

        public static void WriteLine(params object[] oObjects)
        {
            foreach (object o in oObjects)
            {
                System.Diagnostics.Debug.WriteLine(o);
            }
            //System.Diagnostics.Debug.WriteLine();
            
        }

        /// <summary>
        /// Transforms the given point into screen coordinates
        /// </summary>
        /// <param name="point"></param>
        public static PointF GetTransformedPoint(PointF point)
        {
            if (Utility.DrawPanel == null || Utility.DrawPanel.pnlCanvas == null || Utility.DrawPanel.InvokeRequired)
                return point;
            return Utility.DrawPanel.pnlCanvas.GetTransformedPoint(point);
        }

        public static PointF GetMin(PointF a, PointF b)
        {
            PointF result = a;
            if (b.X < result.X) result.X = b.X;
            if (b.Y < result.Y) result.Y = b.Y;
            return result;
        }

        public static PointF GetMax(PointF a, PointF b)
        {
            PointF result = a;
            if (b.X > result.X) result.X = b.X;
            if (b.Y > result.Y) result.Y = b.Y;
            return result;
        }

        public static PointF GetRelative(PointF a, PointF b)
        {
            float x = a.X - b.X;
            float y = a.Y - b.Y;
            return ModifyPoint( new PointF(x, y) );
        }
        public static VisualCanvas GetCanvas()
        {
            return DrawPanel.pnlCanvas;
        }
        public static DrawPanel GetDrawPanel() { return DrawPanel; } 
        public static DrawPanel DrawPanel
        {
            get
            {
                if (Program.Form != null)
                    return Program.Form.drawPanel1;
                return null;
            }
        }
        
        public static void GenerateBottomRoundedRectangle(GraphicsPath oPath, RectangleF target)
        {
            float dPercent = 0.2f;
            float dXStep = target.Width * dPercent;
            float dYStep = target.Height * dPercent;

            // ok .. the lines above generate a non-uniformly rounded rectangle ... but
            // as herbert wants to change that ... here the fix

            dXStep = Math.Min(dXStep, dYStep); dYStep = dXStep;

            oPath.AddLine(target.Left, target.Bottom - dYStep, target.Left, target.Top );            
            oPath.AddLine(target.Left, target.Top, target.Right, target.Top);            

            oPath.AddLine(target.Right, target.Top, target.Right, target.Bottom - dXStep);
            oPath.AddArc(target.Right - dXStep, target.Bottom - dYStep, dXStep, dYStep, 360f, 90f);

            oPath.AddLine(target.Right - dXStep, target.Bottom, target.Left + dXStep, target.Bottom);
            oPath.AddArc(target.Left, target.Bottom - dYStep, dXStep, dYStep, 90f, 90f);

            oPath.CloseFigure();
        }

        public static void GenerateRoundedRectangle(GraphicsPath oPath, RectangleF target)
        {
            float dPercent = 0.2f;
            float dXStep = target.Width * dPercent;
            float dYStep = target.Height * dPercent;

            // ok .. the lines above generate a non-uniformly rounded rectangle ... but
            // as herbert wants to change that ... here the fix

            dXStep = Math.Min(dXStep, dYStep); dYStep = dXStep;

            oPath.AddLine(target.Left, target.Bottom - dYStep, target.Left, target.Top + dYStep);
            oPath.AddArc(target.Left, target.Top, dXStep, dYStep, 180f, 90f);

            oPath.AddLine(target.Left + dYStep, target.Top, target.Right - dYStep, target.Top);
            oPath.AddArc(target.Right - dXStep, target.Top, dXStep, dYStep, 270f, 90f);

            oPath.AddLine(target.Right, target.Top + dXStep, target.Right, target.Bottom - dXStep);
            oPath.AddArc(target.Right - dXStep , target.Bottom -dYStep , dXStep, dYStep, 360f, 90f);

            oPath.AddLine(target.Right - dXStep, target.Bottom, target.Left + dXStep, target.Bottom);
            oPath.AddArc(target.Left, target.Bottom -  dYStep, dXStep, dYStep, 90f, 90f);

            //oPath.AddArc(new RectangleF(target.Left, target.Top, target.Width, target.Width), 180f, 90f);
            //oPath.AddArc(new RectangleF(target.Right, target.Top, target.Width, target.Width), 270f, 90f);
            //oPath.AddArc(new RectangleF(target.Right, target.Bottom, target.Height, target.Height), 360f, 90f);
            //oPath.AddArc(new RectangleF(target.Left, target.Bottom, target.Height, target.Height), 90f, 90f);
            //oPath.AddArc(new RectangleF(target.Left, target.Top, target.Width, target.Height), 180f, 90f);
            //oPath.AddArc(new RectangleF(target.Right, target.Top, target.Width, target.Height), 270f, 90f);
            //oPath.AddArc(new RectangleF(target.Right, target.Bottom, target.Width, target.Height), 360f, 90f);
            //oPath.AddArc(new RectangleF(target.Left, target.Bottom, target.Width, target.Height), 90f, 90f);
            oPath.CloseFigure();
        }

        public static void GenerateRoundedRectangle(GraphicsPath oPath)
        {
            GenerateRoundedRectangle(oPath, new RectangleF(0f, 0f, 10f, 10f));
        }

        public static PointF AddPoints(PointF a, PointF b)
        {
            return new PointF(a.X + b.X, a.Y + b.Y);
        }
        public static PointF SubtractPoints(PointF a, PointF b)
        {
            return new PointF(a.X - b.X, a.Y - b.Y);
        }
        public static float Distance(PointF a, PointF b)
        {
            return (float)Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y));
        }
        /// <summary>
        /// Find the point on the edge of the rectangle that is closest to the point. Inflates the rectangle by the given dist
        /// </summary>
        /// <param name="dim"></param>
        /// <param name="point"></param>
        /// <param name="dist"></param>
        /// <returns></returns>
        public static PointF GetPointOnEdge(RectangleF dim, PointF point, float dist)
        {
            dim.Inflate(dist, dist);

            PointF center = new PointF((dim.Location.X + dim.Width / 2), (dim.Location.Y + dim.Height / 2));
            float slope = Math.Abs((point.Y - center.Y) / (point.X - center.X));

            

            if (Double.IsNaN(slope)) 
                slope = 100;

            if (point.X > center.X)
            {
                if (point.Y > center.Y)
                {
                    if (slope * (dim.Width) > dim.Height)
                        return new PointF(center.X + (dim.Height / 2) / slope, center.Y + (dim.Height / 2));
                    else
                        return new PointF(center.X + (dim.Width / 2), center.Y + slope * (dim.Width / 2));
                }
                else
                {
                    if (slope * (dim.Width) > dim.Height)
                        return new PointF(center.X + (dim.Height / 2) / slope, center.Y - (dim.Height / 2));
                    else
                        return new PointF(center.X + (dim.Width / 2), center.Y - slope * (dim.Width / 2));
                }
            }
            else
            {
                if (point.Y > center.Y)
                {
                    if (slope * (dim.Width) > dim.Height)
                        return new PointF(center.X - (dim.Height / 2) / slope, center.Y + (dim.Height / 2));
                    else
                        return new PointF(center.X - (dim.Width / 2), center.Y + slope * (dim.Width / 2));
                }
                else
                {
                    if (slope * (dim.Width) > dim.Height)
                        return new PointF(center.X - (dim.Height / 2) / slope, center.Y - (dim.Height / 2));
                    else
                        return new PointF(center.X - (dim.Width / 2), center.Y - slope * (dim.Width / 2));
                }
            }
        }
        /// <summary>
        /// Returns a point that is the average of the given set of points
        /// </summary>
        /// <param name="points">list of points to average</param>
        /// <returns></returns>
        public static PointF CenterPoint(List<PointF> points)
        {
            float x = 0, y = 0;
            foreach (PointF p in points)
            {
                x += p.X;
                y += p.Y;
            }
            return new PointF(x / points.Count, y / points.Count);
        }

        public static PointF CenterPoint(List<IDrawable> drawables)
        {
            float x = 0, y = 0;
            foreach (IDrawable id in drawables)
            {
                x += id.Location.X + id.Dimensions.Width/2;
                y += id.Location.Y + id.Dimensions.Height/2;
            }
            return new PointF(x / drawables.Count, y / drawables.Count);
        }

        public static void AlignLeft(List<IDrawable> oList)
        {
            if (oList == null || oList.Count == 0) return;

            HistoryManager.History.SetControllPoint("AlignLeft");

            RectangleF oTemp = GetBounds(oList);
            PointF oTempPoint; 
            foreach (IDrawable d in oList)
            {
                oTempPoint = d.Location;
                oTempPoint.X = oTemp.Left;
                d.Location = oTempPoint;
            }
            Refresh();
        }

        public static void AlignTop(List<IDrawable> oList)
        {
            if (oList == null || oList.Count == 0) return;

            HistoryManager.History.SetControllPoint("AlignTop");
            RectangleF oTemp = GetBounds(oList);

            PointF oTempPoint;
            foreach (IDrawable d in oList)
            {
                oTempPoint = d.Location;
                oTempPoint.Y = oTemp.Top;
                d.Location = oTempPoint;
            }
            Refresh();
        }

        public static void AlignRight(List<IDrawable> oList)
        {
            if (oList == null || oList.Count == 0) return;

            HistoryManager.History.SetControllPoint("AlignRight");

            RectangleF oTemp = GetBounds(oList);

            PointF oTempPoint;
            foreach (IDrawable d in oList)
            {
                oTempPoint = d.Location;
                oTempPoint.X -= (d.Location.X + d.Dimensions.Width) - (oTemp.Right);
                d.Location = oTempPoint;
            }
            Refresh();
        }


        public static void AlignBottom(List<IDrawable> oList)
        {
            if (oList == null || oList.Count == 0) return;

            HistoryManager.History.SetControllPoint("AlignBottom");

            RectangleF oTemp = GetBounds(oList);

            PointF oTempPoint;
            foreach (IDrawable d in oList)
            {
                oTempPoint = d.Location;
                oTempPoint.Y -= (d.Location.Y + d.Dimensions.Height)  - (oTemp.Bottom);
                d.Location = oTempPoint;
            }
            Refresh();
        }


        public static void AlignCenter(List<IDrawable> oList)
        {
            if (oList == null || oList.Count == 0) return;

            HistoryManager.History.SetControllPoint("AlignCenter");

            RectangleF oTemp = GetBounds(oList);

            PointF oTempPoint;
            foreach (IDrawable d in oList)
            {
                oTempPoint = d.Location;
                oTempPoint.X = (oTemp.Left + (oTemp.Width / 2f) - (d.Dimensions.Width / 2f));
                d.Location = oTempPoint;
            }
            Refresh();
        }

        public static void AlignMiddle(List<IDrawable> oList)
        {
            if (oList == null || oList.Count == 0) return;

            HistoryManager.History.SetControllPoint("AlignMiddle");

            RectangleF oTemp = GetBounds(oList);

            PointF oTempPoint;
            foreach (IDrawable d in oList)
            {
                /*if (d is Connector)
                {
                    foreach (Connector.ControlPoint cpt in ((Connector)d).SelectedControlPoints)
                    {
                        oTempPoint = cpt.Point;
                        oTempPoint.Y = (oTemp.Top + (oTemp.Height / 2f));
                        cpt.Point = oTempPoint;
                    }
                }
                else*/
                //{
                    oTempPoint = d.Location;
                    oTempPoint.Y = (oTemp.Top + (oTemp.Height / 2f) - (d.Dimensions.Height / 2f));
                    d.Location = oTempPoint;
                //}
            }
            Refresh();
        }

        public static void DistributeVertically(List<IDrawable> oList)
        {
            if (oList == null || oList.Count <= 2) return;

            HistoryManager.History.SetControllPoint("DistributeVertically");

            RectangleF oTemp = GetBounds(oList);

            oList.Sort(ComparePositionY);

            float dMaxHeight = oList[1].Dimensions.Height;
            float dMinHeight = dMaxHeight;
            float dHeight = 0;
            for (int i = 1; i < oList.Count - 1; i++)
            {
                IDrawable d = oList[i];
                dHeight += d.Dimensions.Height;
                if (d.Dimensions.Width > dMaxHeight) dMaxHeight = d.Dimensions.Height;
                if (d.Dimensions.Width < dMinHeight) dMinHeight = d.Dimensions.Height;
            }

            float dSpace = oList[oList.Count - 1].Location.Y - (oList[0].Location.Y + oList[0].Dimensions.Height);
            int nElements = oList.Count - 2;
            float dDelta = (dSpace - dMaxHeight * ((float)nElements)) / (float)(nElements + 1);

            float dStart = oList[0].Location.Y + oList[0].Dimensions.Height;
            for (int i = 1; i < oList.Count - 1; i++)
            {
                float dPadding = dMaxHeight - (oList[i].Dimensions.Height);
                PointF oLocation = oList[i].Location;
                oLocation.Y = dStart + dDelta + dPadding / 2f;
                oList[i].Location = oLocation;
                dStart = oList[i].Location.Y + oList[i].Dimensions.Height + dPadding / 2f;
            }
            Refresh();

        }

        public static void DistributeHorizontally(List<IDrawable> oList)
        {

            if (oList == null || oList.Count <= 2) return;

            HistoryManager.History.SetControllPoint("DistributeHorizontally");

            RectangleF oTemp = GetBounds(oList);

            oList.Sort(ComparePositionX);

            float dMaxWidth = oList[1].Dimensions.Width;
            float dMinWidth = dMaxWidth;
            float dWidth = 0;
            for (int i = 1; i < oList.Count - 1; i++)
            {
                IDrawable d = oList[i];
                dWidth += d.Dimensions.Width;
                if (d.Dimensions.Width > dMaxWidth) dMaxWidth = d.Dimensions.Width;
                if (d.Dimensions.Width < dMinWidth) dMinWidth = d.Dimensions.Width;
            }            

            float dSpace = oList[oList.Count - 1].Location.X - (oList[0].Location.X + oList[0].Dimensions.Width);
            int nElements = oList.Count - 2;
            float dDelta = (dSpace - dMaxWidth*((float)nElements)) / (float)(nElements + 1);
            
            float dStart = oList[0].Location.X + oList[0].Dimensions.Width;
            for (int i = 1; i < oList.Count - 1; i++)
            {
                float dPadding = dMaxWidth - (oList[i].Dimensions.Width );
                PointF oLocation = oList[i].Location;
                oLocation.X = dStart + dDelta + dPadding/2f ;
                oList[i].Location = oLocation;
                dStart = oList[i].Location.X + oList[i].Dimensions.Width + dPadding / 2f;                
            }
            Refresh();
        }

        public static int ComparePositionX(IDrawable a, IDrawable b)
        {
            return Math.Sign(a.Location.X - b.Location.X);
        }

        public static int ComparePositionY(IDrawable a, IDrawable b)
        {
            return Math.Sign(a.Location.Y - b.Location.Y);
        }

        public static Rectangle ConvertRectangle(RectangleF oRect)
        {
            return Rectangle.Round(oRect);            
        }

        public static Rectangle GetBoundsInt(List<IDrawable> oList)
        {
            return ConvertRectangle(GetBounds(oList));
        }      

        public static RectangleF GetBounds(IEnumerable<IDrawable> oList)
        {                        
            if (oList == null) return new RectangleF();
            RectangleF? result = null; 
            foreach (IDrawable d in oList)
            {
                if (result != null)
                    result = RectangleF.Union(result.Value, d.Bounds);
                else
                    result = d.Bounds;
            }
            return (result == null ? new RectangleF(): result.Value);
        }


        internal static void ShowError(string sCaption, string sMessage)
        {
            MessageBox.Show(sMessage, sCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        public static Bitmap GetResource(string sImageName)
        {
            System.Resources.ResourceManager oManager = new System.Resources.ResourceManager("Athena.Properties.Resources", typeof(MainForm).Assembly);            
            Bitmap bitmap = (Bitmap) oManager.GetObject(sImageName);
            return bitmap;
        }

        public static VisualCanvas GetPanel()
        {
            return Panel;
        }
        public static VisualCanvas Panel
        {
            get
            {
                if (Utility.DrawPanel != null)
                    if (!Utility.DrawPanel.InvokeRequired)
                        return Utility.DrawPanel.pnlCanvas;
                return null;
            }

        }
      
        public static void Refresh()
        {
            if (Utility.DrawPanel != null)
                if (!Utility.DrawPanel.InvokeRequired)
                    Utility.DrawPanel.pnlCanvas.Refresh();
        }
        internal static void SetupToolWindow(ToolStrip oToolstrip)
        {
            //oToolstrip.Items.Add("-");

            oToolstrip.BackColor = System.Drawing.SystemColors.Control;
            ToolStripButton _oSelect = new ToolStripButton(GetResource("Cursor"));//"select");
            _oSelect.ImageScaling = ToolStripItemImageScaling.None;
            _oSelect.Click += new EventHandler(_oSelect_Click);
            oToolstrip.Items.Add(_oSelect);

            //oToolstrip.Items.Add("-");

           

        }

        public static void SetMessage(string sMessage)
        {
            if (Program.Form != null && !Program.Form.InvokeRequired)
            {
                Program.Form.statusLabel.Text = sMessage;
            }
        }

        static void _oSelect_Click(object sender, EventArgs e)
        {
            ToolManager.Instance.DeactivateTools();
            Utility.DrawPanel.CurrentState = DrawPanel.State.Selecting;
            if (sender is ToolStripButton)
            {
                ((ToolStripButton)sender).Checked = true;
            }
            Utility.MouseImage = null;
        }

        internal static bool IsType(Type targetType, Type type)
        {
            if (type == null) return false;
            if (type.IsAbstract) return false;
            if (type == targetType) return true;
            if (type.BaseType == null) return false;
            if (type.BaseType == targetType) return true;
            return IsType(targetType, type.BaseType);
        }
        internal static bool IsTypeNoAbstract(Type targetType, Type type)
        {
            if (type == null) return false;
            //if (type.IsAbstract) return false;
            if (type == targetType) return true;
            if (type.BaseType == null) return false;
            if (type.BaseType == targetType) return true;
            return IsTypeNoAbstract(targetType, type.BaseType);
        }

        public static void BringItemsForward(List<IDrawable> oList, Model oModel)
        {
            if (oList == null || oModel == null || oList.Count == 0) return;
            HistoryManager.History.SetControllPoint("Bring Items Forward");
            foreach (IDrawable oTemp in oList)
            {
                int nIndex = oModel.Drawables.IndexOf(oTemp);
                if (nIndex < oModel.Drawables.Count - 1)
                {
                    oModel.Drawables.Remove(oTemp);
                    oModel.Drawables.Insert(nIndex+1, oTemp);

                }
            }
            Refresh();

        }
        public static void SendItemsBackward(ICollection<IDrawable> oList, Model oModel)
        {
            if (oList == null || oModel == null || oList.Count == 0) return;
            HistoryManager.History.SetControllPoint("Send Items Backward");
            foreach (IDrawable oTemp in oList)
            {
                int nIndex = oModel.Drawables.IndexOf(oTemp);
                if (nIndex >= 1 && oModel.Drawables.Count >= 2)
                {
                    oModel.Drawables.Remove(oTemp);
                    oModel.Drawables.Insert(nIndex-1, oTemp);                    

                }
            }
            Refresh();

        }
        public static void MoveBehindOf(IDrawable drawable, IDrawable target, Model oModel)
        {
            if (drawable == null || oModel == null || drawable == target) return;
            //HistoryManager.History.SetControllPoint("Change Item Position");
            
            int i = oModel.Drawables.IndexOf(target);
            if (i < 0 || i >= oModel.Drawables.Count || i >= oModel.Drawables.IndexOf(drawable)) return;

            oModel.Drawables.Remove(drawable);
            oModel.Drawables.Insert(i, drawable);
            /*
            List<IDrawable> oExludeList = new List<IDrawable>();
            oExludeList.Add(drawable);

            if (drawable.ConnectedDrawables.Count > 0)
            {
                foreach (IDrawable linked in drawable.ConnectedDrawables)
                {                    
                    MoveInFrontOf(linked, drawable, oModel, oExludeList);
                }
            }
            if (drawable.LinkedDrawables.Count > 0)
            {
                foreach (IDrawable linked in drawable.LinkedDrawables)
                {
                    MoveInFrontOf(linked, drawable, oModel, oExludeList);
                }
            }*/
        }

        public static void MoveBehindOf(IDrawable drawable, List<IDrawable> targets, Model oModel)
        {
            if (targets == null || targets.Count < 1 || drawable == null) return;
            int i = oModel.Drawables.IndexOf(targets[0]);
            foreach (IDrawable id in targets)
            {
                int j = oModel.Drawables.IndexOf(id);
                if (j < i) i = j;
            }
            if (i >= oModel.Drawables.IndexOf(drawable)) return;

            oModel.Drawables.Remove(drawable);
            oModel.Drawables.Insert(i, drawable);
        }

        public static void MoveInFrontOf(IDrawable drawable, IDrawable target, Model oModel)
        {
            MoveInFrontOf(drawable, target, oModel, new List<IDrawable>());
        }
        private static void MoveInFrontOf(IDrawable drawable, IDrawable target, Model oModel, List<IDrawable> oExludeList)
        {
            if (drawable == null || oModel == null || drawable == target || oExludeList.Contains(drawable)) return;
            HistoryManager.History.SetControllPoint("Change Item Position");
            
            int i = oModel.Drawables.IndexOf(target);
            if (i <= oModel.Drawables.IndexOf(drawable))
            {
                oExludeList.Add(drawable);
                return;
            }
            oModel.Drawables.Remove(drawable);
            oModel.Drawables.Insert(i, drawable);

            oExludeList.Add(drawable);

            if (drawable.AnchoredItems.Count > 0)
            {
                foreach (IDrawable linked in drawable.AnchoredItems)
                {
                    MoveInFrontOf(linked, drawable, oModel, oExludeList);
                }
            }
        }
        public static void BringItemToFront(IDrawable oTemp, Model oModel)
        {
            if (oTemp == null || oModel == null) return;
            HistoryManager.History.SetControllPoint("Bring Item to Front");
            
            oModel.Drawables.Remove(oTemp);
            oModel.Drawables.Add(oTemp);

            List<IDrawable> oExludeList = new List<IDrawable>();
            oExludeList.Add(oTemp);

            if (oTemp.AnchoredItems.Count > 0)
            {
                foreach (IDrawable linked in oTemp.AnchoredItems)
                {                    
                    Utility.MoveInFrontOf(linked, oTemp, oModel, oExludeList);
                }
            }

            //Refresh();
        }

        public static void BringItemsToFront(ICollection<IDrawable> oList, Model oModel)
        {
            if (oList == null || oModel == null || oList.Count == 0) return;
            HistoryManager.History.SetControllPoint("Bring Items to Front");
            foreach (IDrawable oTemp in oList)
            {
                oModel.Drawables.Remove(oTemp);
                oModel.Drawables.Add(oTemp);
            }
            //Refresh();
        }

        public static void SendItemToBack(IDrawable oDrawable, Model oModel)
        {
            if (oDrawable == null || oModel == null) return;
            HistoryManager.History.SetControllPoint("Send Item to Back");
            oModel.Drawables.Remove(oDrawable);
            oModel.Drawables.Insert(0, oDrawable);

            List<IDrawable> oExludeList = new List<IDrawable>();
            oExludeList.Add(oDrawable);

            if (oDrawable.AnchoredItems.Count > 0)
            {
                foreach (IDrawable linked in oDrawable.AnchoredItems)
                {
                    Utility.MoveInFrontOf(linked, oDrawable, oModel, oExludeList);
                }
            }


            Refresh();
        }


        public static void SendItemsToBack(List<IDrawable> oList, Model oModel)
        {
            if (oList == null || oModel == null || oList.Count == 0) return;
            HistoryManager.History.SetControllPoint("Send Items to Back");
            foreach (IDrawable oTemp in oList)
            {
                oModel.Drawables.Remove(oTemp);
                oModel.Drawables.Insert(0, oTemp);
            }
            Refresh();
        }

        public static float GetMaxStepX()
        {
            float fResult = 10f;
            Athena.Tools.ITool tool = ToolManager.Instance.GetTool("Grid Tool");
            if (tool != null && tool is Athena.Tools.GridTool)
            {
                Athena.Tools.GridTool gridTool = (Athena.Tools.GridTool)tool;
                return gridTool.GridSpaceX;
            }
            return fResult;

        }
        public static float GetMaxStepY()
        {
            float fResult = 10f;
            Athena.Tools.ITool tool = ToolManager.Instance.GetTool("Grid Tool");
            if (tool != null && tool is Athena.Tools.GridTool)
            {
                Athena.Tools.GridTool gridTool = (Athena.Tools.GridTool)tool;
                return gridTool.GridSpaceY;
            }
            return fResult;

        }

        public static void DoTest()
        {
            PointF oStart1 = new PointF(0f, 3f);
            PointF oGrid1 = ModifyPoint(oStart1);
            PointF oExpected = new PointF();
            System.Diagnostics.Debug.Assert(oExpected == oGrid1, "this should have mapped to 0,0");
            oStart1 = new PointF(3f, 3f);
            oGrid1 = ModifyPoint(oStart1);
            System.Diagnostics.Debug.Assert(oExpected == oGrid1, "this should have mapped to 0,0");
            oStart1 = new PointF(4f, 4f);
            oGrid1 = ModifyPoint(oStart1);
            System.Diagnostics.Debug.Assert(oStart1 == oGrid1, "this shouldn't have changed");

        }

        /// <summary>
        /// This function will translocate the given point to the next given 
        /// gridpoint, that is *iff* the grid tool is active
        /// </summary>
        /// <param name="oPoint">The point to translate</param>
        /// <returns>the translated point</returns>
        public static PointF ModifyPoint(PointF oPoint)
        {
            try
            {
                Athena.Tools.ITool tool =  ToolManager.Instance.GetTool("Grid Tool");
                if (tool != null && tool is Athena.Tools.GridTool)
                {
                    Athena.Tools.GridTool gridTool = (Athena.Tools.GridTool)tool;
                    if (!gridTool.DrawGrid) return oPoint;
                    PointF result = oPoint;
                    PointF oGridPoint = gridTool.GetTopGridPointClosestTo(oPoint);

                    if (oPoint.X >= oGridPoint.X - gridTool.MatchParameter * gridTool.GridSpaceX && oPoint.X <= oGridPoint.X + gridTool.MatchParameter * gridTool.GridSpaceX)
                        result.X = oGridPoint.X;
                    else if (oPoint.X >= oGridPoint.X + gridTool.GridSpaceX - gridTool.MatchParameter * gridTool.GridSpaceX && oPoint.X <= oGridPoint.X + gridTool.GridSpaceX + gridTool.MatchParameter * gridTool.GridSpaceX)
                        result.X = oGridPoint.X + gridTool.GridSpaceX;

                    if (oPoint.Y >= oGridPoint.Y - gridTool.MatchParameter * gridTool.GridSpaceY && oPoint.Y <= oGridPoint.Y + gridTool.MatchParameter * gridTool.GridSpaceY)
                        result.Y = oGridPoint.Y;
                    else if (oPoint.Y >= oGridPoint.Y + gridTool.GridSpaceY - gridTool.MatchParameter * gridTool.GridSpaceY && oPoint.Y <= oGridPoint.Y + gridTool.GridSpaceY + gridTool.MatchParameter * gridTool.GridSpaceY)
                        result.Y = oGridPoint.Y + gridTool.GridSpaceY;


                    return result;
                }
                return oPoint;
            }
            catch (Exception)
            {
                return oPoint;
            }
        }

        public class ListConverter<T>
        {
            public List<T> ConvertList(System.Collections.IList listOfObjects)
            {
                T[] temp = new T[ listOfObjects.Count ];
                listOfObjects.CopyTo(temp, 0);
                return new List<T>(temp);            
            }
        }

        public static Image MouseImage
        {
            set 
            {
                if (value == null)
                {
                    DrawPanel.pnlCanvas.MouseCursor = System.Windows.Forms.Cursors.Default;
                }
                else
                {
                    Bitmap b = new Bitmap(value);
                    DrawPanel.pnlCanvas.MouseCursor = new Cursor(b.GetHicon());
                }
            }
        }

        /// <summary>
        /// Find the drawable that is closest to the given point
        /// </summary>
        /// <param name="Refpt"></param>
        /// <param name="drawables"></param>
        /// <returns></returns>
        public static Objects.IDrawable FindClosestDrawable(System.Drawing.PointF Refpt, List<Objects.IDrawable> drawables)
        {
            if (drawables == null || drawables.Count < 1) return null;
            Objects.IDrawable closest = drawables[0];

            float min = Utility.Distance(Refpt, closest.Location), dist = 0;
            foreach (Objects.IDrawable id in drawables)
            {
                dist = Utility.Distance(Refpt, new PointF(id.Location.X + id.Dimensions.Width/2, id.Location.Y + id.Dimensions.Height/2));
                if (dist < min)
                {
                    min = dist;
                    closest = id;
                }
            }
            return closest;
        }

        /// <summary>
        /// Creates an octahedral graphics path ... needs to be transformed
        /// </summary>
        /// <returns>octahedral graphics path</returns>
        public static GraphicsPath CreateBlockPath()
        {
            GraphicsPath oPath = new GraphicsPath();

            oPath.AddLine(0f, 3.5f, 3.5f, 0);
            oPath.AddLine(3.5f, 0f, 8.5f, 0f);
            oPath.AddLine(8.5f, 0f, 12f, 3.5f);
            oPath.AddLine(12f, 3.5f, 12f, 8.5f);
            oPath.AddLine(12f, 8.5f, 8.5f, 12f);
            oPath.AddLine(8.5f, 12f, 3.5f, 12f);
            oPath.AddLine(3.5f, 12f, 0f, 8.5f);
            oPath.AddLine(0f, 8.5f, 0f, 3.5f);

            oPath.CloseFigure();

            return oPath;
        }

        /// <summary>
        /// draws right-angled lines from one point to another
        /// </summary>
        /// <param name="g"></param>
        public static void DrawLines(Graphics g, Pen pen, PointF from, PointF to)
        {
            if (from.Y == to.Y || from.X == to.X)
            {
                g.DrawLine(pen, from.X, from.Y, to.X, to.Y);
                return;
            }
            GraphicsPath path = new GraphicsPath();
            if (from.X <= to.X)
            {
                path.AddLine(from.X, from.Y, (from.X + to.X) / 2, from.Y);
                path.AddLine((from.X + to.X) / 2, from.Y, (from.X + to.X) / 2, to.Y);
                path.AddLine((from.X + to.X) / 2, to.Y, to.X, to.Y);                
            }
            else
            {
                path.AddLine(from.X, from.Y, (from.X + 10), from.Y);
                path.AddLine((from.X + 10), from.Y, (from.X + 10), (from.Y + to.Y) / 2);
                path.AddLine((from.X + 10), (from.Y + to.Y) / 2, (to.X - 10), (from.Y + to.Y) / 2);
                path.AddLine((to.X - 10), (from.Y + to.Y) / 2, to.X - 10, to.Y);
                path.AddLine(to.X - 10, to.Y, to.X, to.Y);
            }
            g.DrawPath(pen, path);
        }

        public static string ConvertColorToARGB(Color oColor)
        {
            return ByteToHex(oColor.A) +
                ByteToHex(oColor.R) +
                ByteToHex(oColor.G) +
                ByteToHex(oColor.B);
        }

        public static string ByteToHex(byte oByte)
        {
            if (oByte == 0)
                return "00";
            string sResult = Convert.ToString(oByte, 16);
            if (sResult.Length == 1)
                sResult = "0" + sResult;
            return sResult;
        }

        public static System.Drawing.Color ConverARGBToColor(String sColor)
        {
            System.Drawing.Color oResult = System.Drawing.Color.Empty;
            if (sColor == String.Empty) throw new Exception("No Color given");

            try
            {
                if (sColor.Length == 8)
                {
                    int nAlpha = Convert.ToInt16(sColor.Substring(0, 2), 16);
                    int nRed = Convert.ToInt16(sColor.Substring(2, 2), 16);
                    int nGreen = Convert.ToInt16(sColor.Substring(4, 2), 16);
                    int nBlue = Convert.ToInt16(sColor.Substring(6, 2), 16);
                    oResult = System.Drawing.Color.FromArgb(nAlpha, nRed, nGreen, nBlue);
                }
                else if (sColor.Length == 6)
                {
                    int nRed = Convert.ToInt16(sColor.Substring(0, 2), 16);
                    int nGreen = Convert.ToInt16(sColor.Substring(2, 2), 16);
                    int nBlue = Convert.ToInt16(sColor.Substring(4, 2), 16);
                    oResult = System.Drawing.Color.FromArgb(255, nRed, nGreen, nBlue);
                }
                else
                {
                    throw new Exception("The Color string has to be in ARGB");
                }

            }
            catch (Exception)
            {
            }
            return oResult;
        }
        
        public static double ReadDouble(string sDouble)
        {
            double dResult = 0.0;
            string sTemp = sDouble;
            if (string.IsNullOrEmpty(sDouble)) return dResult;
            if (sTemp.Contains(",")) sTemp = sTemp.Replace(',', '.');
            if (sTemp.Contains("%")) sTemp = sTemp.Replace("%", "");
            try
            {
                dResult = Convert.ToDouble(sTemp);
            }
            catch (FormatException)
            {

            }
            return dResult;
        }

        public static float ReadSingle(System.Xml.XmlNode oNode, string sAttribute)
        {
            string sTemp = GetAttribute(oNode, sAttribute);
            return (float)ReadDouble(sTemp);
        }

        public static bool ReadBoolean(System.Xml.XmlNode oNode, string sAttribute)
        {
            try
            {
                string sTemp = GetAttribute(oNode, sAttribute);
                return Convert.ToBoolean(sTemp);
            }
            catch (FormatException)
            {
                return false;
            }
        }

        public static double ReadDouble(System.Xml.XmlNode oNode, string sAttribute)
        {
            string sTemp = GetAttribute(oNode, sAttribute);
            return ReadDouble(sTemp);
        }

        public static string GetAttribute(System.Xml.XmlNode oNode, string sAttribute)
        {
            if (oNode == null || oNode.Attributes == null) return String.Empty;

            foreach (System.Xml.XmlAttribute attrib in oNode.Attributes)
            {
                if (attrib.Name == sAttribute)
                    return attrib.Value;
            }

            return String.Empty;
        }

    }
}
